package com.sean.community.comtroller;

import com.google.code.kaptcha.Producer;
import com.sean.community.entity.User;
import com.sean.community.service.UserService;
import com.sean.community.util.CommunityConstant;
import com.sean.community.util.CommunityUtil;
import com.sean.community.util.CookieUtil;
import com.sean.community.util.RedisKeyUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 登录控制器
 */
@Controller
public class LoginController implements CommunityConstant {
    private UserService userService;
    private Producer kaptchaProducer;
    private RedisTemplate<String, Object> redisTemplate;
    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Autowired
    public void setKaptchaProducer(Producer kaptchaProducer) {
        this.kaptchaProducer = kaptchaProducer;
    }

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @RequestMapping(path = "/register", method = RequestMethod.GET)
    public String getRegisterPage(){
        return "site/register";
    }

    @RequestMapping(path = "/register", method = RequestMethod.POST)
    public String register(Model model, User user){
        Map<String, Object> map = userService.register(user);
        if(map == null || map.isEmpty()){
            model.addAllAttributes(new ModelMap("msg", "注册成功，我们已经向您的邮箱发送了一封激活邮件，请尽快激活您的账号"));
            model.addAllAttributes(new ModelMap("target", "/index"));
            return "site/operate-result";
        }else{
            model.addAllAttributes(new ModelMap("usernameMsg", map.get("usernameMsg")));
            model.addAllAttributes(new ModelMap("passwordMsg", map.get("passwordMsg")));
            model.addAllAttributes(new ModelMap("emailMsg", map.get("emailMsg")));
            return "site/register";
        }
    }


    // http://127.0.0.1:8080/community/activation/uid/code
    @RequestMapping(path="/activation/{userId}/{code}", method = RequestMethod.GET)
    public String activation(Model model, @PathVariable("userId") int userId, @PathVariable("code") String code){
        int result = userService.activation(userId, code);
        if(result == ACTIVATION_SUCCESS){
            model.addAllAttributes(new ModelMap("msg", "恭喜您激活成功，您的账号已可以正常使用了！"));
            model.addAllAttributes(new ModelMap("target", "/login"));
        }else if(result == ACTIVATION_REPEAT){
            model.addAllAttributes(new ModelMap("msg", "请勿重复操作，您的账号账号已激活！"));
            model.addAllAttributes(new ModelMap("target", "/index"));
        }else{
            model.addAllAttributes(new ModelMap("msg", "抱歉激活失败, 请检查您的激活码是否正确或稍后重试！"));
            model.addAllAttributes(new ModelMap("target", "/index"));
        }
        return "site/operate-result";
    }

    @RequestMapping(path = "/login", method = RequestMethod.GET)
    public String getLoginPage(){
        return "site/login";
    }

    @RequestMapping(path = "/kaptcha", method = RequestMethod.GET)
    public void getKaptcha(HttpServletResponse response /*, HttpSession session*/){
        // 生成验证码
        String kaptchaText = kaptchaProducer.createText();
        BufferedImage image = kaptchaProducer.createImage(kaptchaText);

        // 将验证码存入 Session ---改为---> 存入 Redis
        // session.setAttribute("kaptchaText", kaptchaText);   // 将验证码存入 Session
        String kaptchaOwner = CommunityUtil.generateUUID();     // 验证码归属
        Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);   // 将验证码归属存到 cookie 中
        cookie.setMaxAge(60);
        cookie.setPath(contextPath);
        response.addCookie(cookie);
        String kaptchaKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);   // 获取 Redis key
        redisTemplate.opsForValue().set(kaptchaKey, kaptchaText, 60, TimeUnit.SECONDS);       // 将验证码存到 Redis

        // 将图片输出给浏览器
        response.setContentType("image/png"); // 声明输出类型
        try {
            OutputStream outputStream = response.getOutputStream();
            ImageIO.write(image, "png", outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("响应验证码失败：" + e.getMessage());
        }
    }

    /**
     *
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @param rememberMe 是否记住我
     * @param model 模型
     * @param response 响应
     * @param kaptchaOwner 验证码归属
     * @return 登录成功跳转到首页，失败返回登录页
     */
    @RequestMapping(path = "/login", method = RequestMethod.POST)
    public String login(String username, String password, String code, boolean rememberMe,
                        Model model, /*HttpSession session,*/ HttpServletResponse response,
                        @CookieValue("kaptchaOwner") String kaptchaOwner){
        // 检查验证码
        // String kaptchaText = (String) session.getAttribute("kaptchaText");  // 从 session 中获取验证码，改为从 redis 中获取验证码
        String kaptchaText = null;
        if(StringUtils.isNoneBlank(kaptchaOwner)){
            String kaptchaKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
            kaptchaText = (String)redisTemplate.opsForValue().get(kaptchaKey);   // 从 redis 中获取验证码
        }
        if(StringUtils.isBlank(code) ||
           StringUtils.isBlank(kaptchaText) ||
           !kaptchaText.equalsIgnoreCase(code)){
            model.addAllAttributes(new ModelMap("kaptchaMsg", "验证码错误！"));
            return "site/login";
        }
        // 检查账号密码
        // 没有记住我：12 小时
        // 记住我：一个月
        int expiredSeconds = rememberMe ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
        Map<String, Object> map = userService.login(username, password, expiredSeconds);
        // 登录成功
        if(map.containsKey("ticket")){
            Cookie cookie = new Cookie("ticket", (String)map.get("ticket"));
            cookie.setPath(contextPath);
            cookie.setMaxAge(expiredSeconds);
            response.addCookie(cookie);
            return "redirect:/index";
        }else{  // 登录失败
            model.addAllAttributes(new ModelMap("usernameMsg", map.get("usernameMsg")));
            model.addAllAttributes(new ModelMap("passwordMsg", map.get("passwordMsg")));
            return "site/login";
        }
    }

    @RequestMapping("/logout")
    public String logout(@CookieValue("ticket") String ticket){
        userService.logout(ticket);
        SecurityContextHolder.clearContext();
        return "redirect:/login";
    }

    /* 下面是忘记密码的部分 */
    @RequestMapping(path = "/forget", method = RequestMethod.GET)
    public String getForgetPage(){
        return "site/forget";
    }

    // 异步获取验证码
    @RequestMapping(path = "/forgetKaptcha", method = RequestMethod.POST)
    @ResponseBody
    public String getForgetKaptcha(String email){
        final Map<String, Object> map = userService.getForgetKaptcha(email);
        if(map == null || map.isEmpty()){
            return CommunityUtil.getJSONString(200, "我们已将验证码发送至您的邮箱，请注意查收！");
        }else{
            return CommunityUtil.getJSONString(500, (String)map.get("msg"));
        }
    }

    // 修改密码
    @RequestMapping(path = "/forget/updatePassword", method = RequestMethod.POST)
    public String updatePassword(String email, String kaptcha, String newPassword, Model model){
        // 检查验证码
        final String redisKey = RedisKeyUtil.getForgetKaptcha(email);
        final String forgetKaptcha = (String)redisTemplate.opsForValue().get(redisKey);     // 从 Redis 中得到验证码
        if(StringUtils.isBlank(kaptcha) ||
                StringUtils.isBlank(forgetKaptcha) ||
                !forgetKaptcha.equalsIgnoreCase(kaptcha)){
            model.addAttribute("kaptchaMsg", "验证码错误！");
            model.addAttribute("email", email);
            return "site/forget";
        }
        // 更新密码
        final Map<String, Object> map = userService.updatePasswordByEmail(email, newPassword);
        if(map == null || map.isEmpty()){
            model.addAllAttributes(new ModelMap("msg", "修改密码成功，请前往登录！"));
            model.addAllAttributes(new ModelMap("target", "/login"));
            return "site/operate-result";
        }else{
            model.addAllAttributes(new ModelMap("emailMsg", map.get("emailMsg")));
            model.addAllAttributes(new ModelMap("passwordMsg", map.get("passwordMsg")));
            return "site/forget";
        }
    }
}
